#!/usr/bin/env python
# -*- coding: utf-8 -*-
#  views.py
#  description

#  Created by zhouzongli633 on 2020/8/3 3:58 下午.
#  Copyright ©Intellectus All rights reserved.

import datetime
import json
import random
import string
from threading import Thread

from django.http import HttpResponse

from Baby.models import Users
from Baby.models import UsersBabies
from Common import bcrypt
from Common.decorators import check_body, method, check_param
from Common.emailManager import send_password_reset
from Common.logger import app_log, gen_log
from Common.response import resp
from User import user_helper
from User.models import FeedBacks, PushNotifications, Posts, Comments, Notifications
from User.models import QuestionResponses
from User.models import UserFamilyInvitationCode
from django.views.decorators.http import require_http_methods


@method(['POST'])
@check_body(['user_id'])
def user_community_info(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)
        posts_count = len(user.posts.all())
        comments_count = len(user.comments.all())
        history_count = 0
        notice_count = len(user.notifications.all())
        ret = {
            "posts_count": posts_count,
            "comments_count": comments_count,
            "history_count": history_count,
            "notice_count": notice_count,
            "user_info": user.user_tojson()
        }
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'nickname', 'avatar'])
def update_user_info(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)
        user.full_name = params['nickname']
        user.file_name = params['avatar']
        user.save()
        return resp(0, user.user_tojson())

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def get_user_post_list(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)
        posts_records = user.posts.all()
        ret = []
        for post in posts_records:
            ret.append(post.posts_include_media_to_json())
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def get_user_comment_list(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)

        comments = user.comments.all()
        ret = []
        for it in comments:
            if it.post:
                ret.append(it.post.posts_include_media_to_json())
            elif it.feed_id:
                pass
            elif it.milestone_id:
                pass
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def get_user_history(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)
        ret = []
        # todo - user history
        bookmarked = []
        view_history = []

        ret.extend(bookmarked)
        ret.extend(view_history)

        return resp(0, ret)

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def get_user_notifycations(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['user_id']).first()
        if not user:
            return resp(4001)
        ret = []
        notifications = user.notifications.all()
        for notify in notifications:
            ret.append(notify.notification_to_json())

        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'filter'])
def content_index(request):
    try:
        # todo : filter[all,post,education,milestone,update,unread]
        params = json.loads(request.body)
        filt = params['filter']

        family = user_helper.get_all_family_members(params['user_id'])
        req_posts = Posts.objects.filter(user_id__in=family).all()
        posts = [record.posts_include_media_to_json() for record in req_posts]

        ret = {
            'posts': posts,
            'content': None,
            'users': None,
            'daily_update': None,
            'special_cards': None,
            'nicu_journey_data': None
        }
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body([])
def tokens(request):
    try:
        access_token = request.META.get("HTTP_X_ACCESS_TOKEN")
        refresh_token = request.META.get("HTTP_X_REFRESH_TOKEN")

        user = Users.objects.filter(access_token=access_token, refresh_token=refresh_token).first()
        status = 401
        ret = {'error': 'Not Authorized'}
        if user:
            token_info = user_helper.process_tokens(user)
            ret = token_info
            status = 200
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['email', 'password', 'full_name'])
def signup(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['email']).first()

        if not user:
            return resp(5001)
        if user and user.password:
            return resp(5002)
        elif user and user.password is None:
            user.password = bcrypt.Bcrypt.encrypt(params['password'])
            user.save()
        else:
            resp(-1)
        # save user image
        if 'user_picture' in params and params['user_picture']:
            user.file_name = params['user_picture']
            user.save()

        response = {}
        user_j = user.user_tojson()
        response['user'] = user_j

        if 'babies' in params and params['babies']:
            for baby in params['babies']:
                baby_id = str(baby['id'])
                users_baby = UsersBabies.objects.filter(users_id=user.id, baby_id=baby['id']).first()
                users_baby.file_name = params['file_name']
                users_baby.save()
            babys = user_helper.fetch_babies_with_user(user)
            response['babies'] = babys
        response['tokens'] = user_helper.process_tokens(user)
        # manager = ScheduleManager()
        # manager.member_signup_worker(user_id=user.id)

        # todo - worker
        if user.relationship == 'father' or user.relationship == 'mother':
            gen_log.info('User is a parent')
            for it in babys:
                q_r = QuestionResponses(
                    baby_id=it['id'], user_id=user.id, question_id=1, answer='Yes'
                )

            # QuestionResponseWorker.perform_async(user.id, babies.first['id'], 1, 'Yes')
            # SignupQuestionsWorker.perform_async(user.id)
        return resp(0, response)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['email', 'password'])
def login(request):
    try:
        res = {}
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['email']).first()
        if not user:
            return resp(5001, "email not exist")
        r = bcrypt.Bcrypt.check(params['password'], user.password)
        if r:
            token = user_helper.process_tokens(user)
            res['user'] = user.user_tojson()
            res['babies'] = user_helper.fetch_babies_with_user(user)
            res['tokens'] = token

            return resp(0, data=res, ruby=False)

        else:
            return resp(5001)

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['email'])
def logout(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['email']).first()
        if user:
            user.access_token = None
            user.refresh_token = None
            user.token_expiry_time = datetime.datetime.utcnow()
            user.save()
        resp(0)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['email'])
def check(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['email']).first()
        r = ''
        if user and not user.is_parent:
            if user.password:
                r = 'You have already signed up. Please login!'
            else:
                r = 'You already have an invitation. Please check your email.'

        return resp(0, {"message": r})
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['email'])
def reset(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(email=params['email']).first()
        if not user:
            return resp(4001)
        random_password = "".join(
            random.sample([x for x in string.ascii_uppercase + string.ascii_lowercase + string.digits], 8))
        thr = Thread(target=send_password_reset, args=(params['email'], random_password))
        thr.start()
        user.password = bcrypt.Bcrypt.encrypt(random_password)
        user.save()
        return resp(0, 'If you have a registered account with us, then you should be getting an email shortly.')
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


# 'qvZsrNn4'

@method(['POST'])
@check_body(['code'])
def beta_check(request):
    try:
        params = json.loads(request.body)
        if 'code' in params and int(params['code']) == 642824663:
            return resp(0, {'status': 'Success'})
        else:
            return resp(0, {'status': 'Invalid code. Please ask your nurse to give you the correct code.'})

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['full_name', 'relationship', 'email', 'user_id'])
def invite(request):
    try:
        params = json.loads(request.body)
        existing_family_user = Users.objects.filter(email=params['email']).first()
        if existing_family_user:
            return resp(5003)

        member, family_user = user_helper.create_family_member(params)
        if not member:
            return resp(5004)
        create_invitation = user_helper.create_invitation(member, family_user)
        if create_invitation['code_created']:
            return resp(0, 'invitation success')
        else:
            return resp(5005)

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['invitation_code', 'email'])
def check_invite(request):
    try:
        params = json.loads(request.body)

        if len(str(params['invitation_code'])) != 6:
            return resp(5006)
        inviter = Users.objects.filter(email=params['email']).first()
        security_code = UserFamilyInvitationCode.objects.filter(invitation_code=params['invitation_code']).first()

        user = Users.objects.filter(security_code=params['invitation_code']).first()
        if user and user.is_parent and params['email'].lower() == 'smartnicu2home@gmail.com':
            return resp(0, user.user_tojson())
        elif not security_code or not inviter or security_code.security_code != inviter.security_code:
            return resp(5007)
        else:
            user = Users.objects.filter(security_code=params['invitation_code']).first()
            return resp(0, user.user_tojson())

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'security_code'])
def update(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id'], security_code=params['security_code']).first()
        if not user:
            return resp(4001)
        ret = {}
        if 'file_name' in params:
            user.file_name = params['file_name']
        if 'email' in params:
            user.email = params['email']
        if 'full_name' in params:
            user.full_name = params['full_name']
        user.save()
        ret['file_name'] = user.file_name
        ret['message'] = 'Successfully update your details.'
        return resp(0, ret)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'security_code', 'current_password', 'new_password'])
def update_password(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id'], security_code=params['security_code']).first()
        if not user:
            return resp(4001)
        if len(params['new_password']) < 8:
            return resp(5009)
        r = bcrypt.Bcrypt.check(params['current_password'], user.password)
        if r:
            user.password = bcrypt.Bcrypt.encrypt(params['new_password'])
            user.save()
            return resp(0, 'Successfully updated password!')
        else:
            return resp(5008)

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['GET'])
@check_param(['user_id'])
def invite_data(request):
    try:
        response = {}
        members = []
        user_id = request.GET.get('user_id')
        user = Users.objects.filter(id=user_id).first()
        if not user:
            return resp(4001)
        family_members = user_helper.get_all_invited_members(user_id)
        if family_members:
            for member_user in Users.objects.filter(id__in=family_members).all():
                if member_user.id == user_id:
                    continue
                member_response = {
                    'name': member_user.full_name,
                    'id': member_user.id,
                    'file_name': member_user.file_name,
                    'relationship': member_user.relationship,
                    'email': member_user.email,
                    'connected': True if member_user.password else False
                }
                members.append(member_response)

        response['members'] = members
        return resp(0, response)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'feedback'])
def feedback(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id']).first()
        if not user:
            return resp(4001)
        feed_back = FeedBacks(
            user_id=params['user_id'],
            response=params['feedback']
        )
        feed_back.save()
        return resp(0, feed_back.feed_backs_to_json())
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def delete(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id'], security_code=params['security_code'])
        family_member = Users.objects.filter(id=params['family_member_id'])
        user_babies = UsersBabies.objects.filter(users_id=params['user_id']).values('baby_id').all()
        family_member_babies = UsersBabies.objects.filter(users_id=params['family_member_id']).values('baby_id').all()
        if user and (user.relationship.lower() == 'father' or user.relationship.lower() == 'mother') \
                and family_member and user_babies == family_member_babies:
            pass
            app_log.info('Delete family member.')
            # todo - deleet family member
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id'])
def pending_surveys(request):
    try:
        android_version = '2.0.1'
        ios_version = '2.2.0.1'
        client = request.headers['HTTP_X_CLIENT']
        app_version = request.headers['HTTP_X_APP_VERSION']

        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id'])
        babysense_r = user_helper.pending_survey(user.id)

        if babysense_r['survey_link']:
            babysense_r['salutation'] = "Hi {}".format(user.full_name) if user else "Hello"
            babysense_r[
                'survey_description'] = 'Please take a moment to answer these survey questions so we can better ' \
                                        'understand your experience in the NICU. This will allow us to ' \
                                        'help you and other families like you.'
            babysense_r['survey_team_name'] = "Thanks.\nNICU2HOME Team"
            buttons = []
            buttons.append({'title': 'Answer Now', 'action': 'link', 'url': babysense_r['survey_link']})
            buttons.append({'title': 'Remind me Later', 'action': 'dismiss'})
            babysense_r['buttons'] = buttons
        else:
            # todo - nps_needed?
            pass
        return resp(0, babysense_r)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST', 'GET'])
def notification_settings(request):
    try:
        if request.method == 'GET':
            user_id = request.GET.get('user_id')
            user = Users.objects.get(id=user_id)
            if not user:
                return resp(4001)
            ret = {
                "recommended_notifications": user.recommended_notifications,
                "post_notifications": user.post_notifications,
                "comment_notifications": user.comment_notifications,
                "daily_update_notifications": user.daily_update_notifications,
                "scheduled": user.scheduled,
                "scheduled_from": "{}".format(user.scheduled_from),
                "scheduled_to": "{}".format(user.scheduled_to),

            }
            return resp(0, ret)

        elif request.method == 'POST':
            params = json.loads(request.body)
            user = Users.objects.get(id=params['user_id'])
            if not user:
                return resp(code=4001)

            if 'recommended_notifications' in params:
                user.recommended_notifications = params['recommended_notifications']
            if 'post_notifications' in params:
                user.post_notifications = params['post_notifications']
            if 'comment_notifications' in params:
                user.comment_notifications = params['comment_notifications']
            if 'daily_update_notifications' in params:
                user.daily_update_notifications = params['daily_update_notifications']
            if 'scheduled' in params:
                user.scheduled = params['scheduled']
                if params['scheduled'] and 'scheduled_from' in params and 'scheduled_to' in params:
                    user.scheduled_from = params['scheduled_from']
                    user.scheduled_to = params['scheduled_to']
            user.save()
            ret = {
                "recommended_notifications": user.recommended_notifications,
                "post_notifications": user.post_notifications,
                "comment_notifications": user.comment_notifications,
                "daily_update_notifications": user.daily_update_notifications,
                "scheduled": user.scheduled,
                "scheduled_from": "{}".format(user.scheduled_from),
                "scheduled_to": "{}".format(user.scheduled_to),
            }

            return resp(0, ret)
        return resp(3001)

    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))


@method(['POST'])
@check_body(['user_id', 'security_code', 'os', 'push_token'])
def push_notif_token(request):
    try:
        params = json.loads(request.body)
        user = Users.objects.filter(id=params['user_id'], security_code=params['security_code']).first()
        if not user:
            return resp(4001)
        user_agent = "android" if params['os'].lower() == 'android' else 'ios'
        push_notification = user.push_notifications.first()
        if push_notification:
            app_log.info('User already had an old notification token, updating it...')
            push_notification.token = params['push_token']
            push_notification.user_agent = user_agent
            push_notification.save()
        else:
            token_r = PushNotifications(
                token=params['push_token'],
                user=user,
                user_agent=user_agent
            )
            token_r.save()
        return resp(0)
    except Exception as e:
        app_log.exception(e)
        return resp(-1, str(e))
